using System;
using System.Collections.Generic;
using System.Linq;

using Csla;

using EntModApp.EntServices.Business;
using EntModApp.EntServices.IoC;

using DemoApp.DataAccess;

namespace DemoApp.BusinessLayer 
{
  [Serializable]
  public partial class CslaGroupInfoCollection
    : ReadOnlyListBase<CslaGroupInfoCollection, CslaGroupInfo>,
    IBusinessObjectCollection<IGroup>
  {
    #region [ Business Properties ]

    public int TotalItems { get; private set; }

    #endregion [ Business Properties ]

    #region [ Factory Methods ]
    public static int GetCount(GroupLoadSettings loadSettings = null)
    {
      loadSettings = GroupLoadSettings.FromGroupLoadSettings(loadSettings);
      var cmd = new GetCountCommand { LoadSettings = loadSettings };
      DataPortal.Execute(cmd);
      return cmd.Count;
    }

    public static CslaGroupInfoCollection GetGroupInfoById(Guid UserId, GroupLoadSettings loadSettings = null)
    {
      return GetGroupInfoById(new UserKey { UserId = UserId }, loadSettings);
    }

    public static CslaGroupInfoCollection GetGroupInfoById(UserKey key, GroupLoadSettings loadSettings = null)
    {
      if (key == null) throw new ArgumentNullException("key");
      loadSettings = GroupLoadSettings.FromGroupLoadSettings(loadSettings);
      loadSettings.Filter.ByKey = key;
      var criteria = new GetAllCriteria
      {
        LoadSettings = loadSettings,
      };
      var result = DataPortal.Fetch<CslaGroupInfoCollection>(criteria);
      return result;
    }

    public static CslaGroupInfoCollection GetGroupInfoCollection(GroupLoadSettings loadSettings = null)
    {
      loadSettings = GroupLoadSettings.FromGroupLoadSettings(loadSettings);
      var criteria = new GetAllCriteria
      {
        LoadSettings = loadSettings,
      };
      var result = DataPortal.Fetch<CslaGroupInfoCollection>(criteria);
      return result;
    }

    protected internal static CslaGroupInfoCollection GetGroupInfoCollection(IEnumerable<Group> data, GroupLoadSettings loadSettings)
    {
      if (data == null) throw new ArgumentNullException("data");
      if (loadSettings == null) throw new ArgumentNullException("loadSettings");
      var result = new CslaGroupInfoCollection();
      result.FetchAll(data, loadSettings);
      result.TotalItems = result.Count;
      return result;
    }

    private static int ForceInit = 0;
    protected CslaGroupInfoCollection()
    {
      ForceInit = 1;
    }

    #region [ Criterias ]

    [Serializable]
    class GetAllCriteria : CriteriaBase<GetAllCriteria>//, ICriteriaBase
    {
      public GroupLoadSettings LoadSettings { get; set; }
    }
    #endregion

    #endregion

    #region [ Commands ]
    [Serializable]
    class GetCountCommand : CommandBase<GetCountCommand>
    {
      public GroupLoadSettings LoadSettings { get; set; }

      public int Count { get; private set; }

      protected override void DataPortal_Execute()
      {
        var dbFactory = ServiceLocator.Current.GetInstance<IDemoAppModelDataRepositoryFactory>();
        using (var db = dbFactory.CreateRepository())
        {
          Count = db.Groups.Count(LoadSettings);
        }
      }
    }
    #endregion [ Commands ]

    #region [ Data Access ]
    private void DataPortal_Fetch(GetAllCriteria criteria)
    {
      var dbFactory = ServiceLocator.Current.GetInstance<IDemoAppModelDataRepositoryFactory>();
      IEnumerable<Group> data;
      using (var db = dbFactory.CreateRepository())
      {
        int total;
        data = db.Users.Retrieve(criteria.LoadSettings, out total).Cast<Group>();
        TotalItems = total;
      }
      FetchAll(data, criteria.LoadSettings);
    }

    private void FetchAll(IEnumerable<Group> data, GroupLoadSettings loadSettings)
    {
      var oldIsReadOnly = IsReadOnly;
      var oldRaiseListChangedEvents = RaiseListChangedEvents;
      try
      {
        IsReadOnly = false;
        RaiseListChangedEvents = false;

        foreach (var item in data)
        {
          var element = CslaGroupInfo.GetGroupInfo(item, loadSettings);
          this.Add(element);
        }
      }
      finally
      {
        IsReadOnly = oldIsReadOnly;
        RaiseListChangedEvents = oldRaiseListChangedEvents;
      }
    }
    #endregion

    #region [ Explicit IBusinessObjectCollection<IGroup> implementation ]
    void ICollection<IGroup>.Add(IGroup item)
    {
      this.Add((CslaGroupInfo)item);
    }

    void ICollection<IGroup>.Clear()
    {
      this.Clear();
    }

    bool ICollection<IGroup>.Contains(IGroup item)
    {
      return this.Contains((CslaGroupInfo)item);
    }

    void ICollection<IGroup>.CopyTo(IGroup[] array, int arrayIndex)
    {
      int size = Math.Min(array.Length - arrayIndex, this.Count);
      if (size > 0)
      {
        var a = new CslaGroupInfo[size];
        this.CopyTo(a, 0);
        Array.Copy(a, 0, array, arrayIndex, size);
      }
    }

    bool ICollection<IGroup>.IsReadOnly
    {
      get { return true; }
    }

    bool ICollection<IGroup>.Remove(IGroup item)
    {
      return this.Remove((CslaGroupInfo)item);
    }

    IEnumerator<IGroup> IEnumerable<IGroup>.GetEnumerator()
    {
      return this.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return this.GetEnumerator();
    }

    bool IBusinessObject.IsReadonly
    {
      get { return true; }
    }

    bool IBusinessObject.IsDirty
    {
      get { return false; }
    }

    IGroup IBusinessObjectCollection<IGroup>.this[int index]
    {
      get
      {
        return this[index];
      }
      set
      {
        this[index] = (CslaGroupInfo)value;
      }
    }
    #endregion [ Explicit IBusinessObjectCollection<IGroup> implementation ]
  }
}
